#pragma once
#include <vector>
#include <map>
#include <string>
#include <cms/ConnectionFactory.h>
#include <google/protobuf/message.h>

//owner
#include "eventagent.h"
#include "messageargs.h"
#include "eventagentsupport.h"
#include "connectionmanager.h"


class ConnectionConfig;
class CommandConfig;

class FactoryManager
{
public:
	typedef std::map<std::string, cms::ConnectionFactory*> FactoryType;
private:
	std::map<std::string, cms::ConnectionFactory*> factories;
	std::vector<ConnectionManager*> connections;
	ConnectionConfig* config;

public:
	FactoryManager(ConnectionConfig* config);
	~FactoryManager(void);
	void send(const std::string& commandName,  google::protobuf::Message* message);
	template<typename tyR>
	tyR call(const std::string& commandName,  google::protobuf::Message* message);
	void listen(const std::string& commandName);
	void stopListen(const std::string& commandName);

	void removeFactory(std::string& factoryName);
	void removeConnection(std::string& connectionName);

	template<typename Tt>
	IEventAgent<MessageArgs>* registerMessageEventHandler(const std::string& commandName, Tt* target);
private:
	//ConnectionManager* getOrCreateConnectionManager(CommandConfig* cmdCfg);
	ConnectionManager* getOrCreateConnectionManager(const std::string& cmdName);
	ConnectionManager* getConnectionManager(const std::string& cmdName);
	cms::ConnectionFactory*  getOrCreateFactory(const std::string& factoryName);
	cms::ConnectionFactory* getFactory(const std::string& factoryName);
};

template<typename tyR>
tyR FactoryManager::call(const std::string& commandName,  google::protobuf::Message* message)
{
	ConnectionManager* connMgr = getOrCreateConnectionManager(commandName);
	return dynamic_cast<tyR>(connMgr->call(config->getCommandConfig(commandName), message));
}

template<typename Tt>
IEventAgent<MessageArgs>* FactoryManager::registerMessageEventHandler(const std::string& commandName, Tt* target)
{
	ConnectionManager* connMgr = getOrCreateConnectionManager(commandName);
	EventAgent<ConnectionManager,Tt, MessageArgs>* agent = new EventAgent<ConnectionManager,Tt, MessageArgs>(connMgr, target);
	//return dynamic_cast<IEventAgent<MessageArgs>* >(agent);
	return agent;

}